package com.silence.gmall.aop;

import com.alibaba.fastjson2.JSON;
import com.silence.gmall.base.Result;
import com.silence.gmall.enums.CommonCode;
import com.silence.gmall.exception.ServiceException;
import io.micrometer.observation.Observation;
import io.micrometer.observation.ObservationRegistry;
import io.micrometer.tracing.Tracer;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;

import java.lang.reflect.Method;
import java.time.Instant;
import java.util.Optional;

/**
 * 响应增强AOP，为所有控制器响应添加跟踪信息
 * <p>
 * 该AOP会拦截所有控制器方法，并自动为返回的Result对象添加:
 * - traceId: 分布式跟踪ID
 * - spanId: 当前请求的跨度ID
 * - timestamp: 响应时间戳
 * </p>
 *
 * @author silence
 * @since 2025-06-11
 */
@Slf4j
@Aspect
@Order(0)
@Component
@RequiredArgsConstructor
public class ResponseEnhanceAop {

    /**
     * 跟踪器，用于获取当前请求的跟踪信息
     */
    private final Tracer tracer;

    /**
     * 观察仓库，用于创建观察上下文
     */
    private final ObservationRegistry observationRegistry;

    /**
     * 匹配所有controller包下以Controller结尾的类的所有方法
     */
    @Pointcut("execution(* com.silence..*Controller.*(..)) && " +
            "!execution(* com.silence..web..*(..))")
    public void controllerMethods() {
        // 切点定义，无需实现
    }

    /**
     * 环绕通知，增强控制器响应
     *
     * @param joinPoint 连接点
     * @return 原始或增强后的结果
     */
    @Around("controllerMethods()")
    public Object enhanceResponse(ProceedingJoinPoint joinPoint) {
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        String methodName = method.getName();
        String className = method.getDeclaringClass().getSimpleName();
        String fullMethodPath = className + "#" + methodName;

        // 创建观察上下文
        return Observation
                .createNotStarted(fullMethodPath, observationRegistry)
                .contextualName("controller." + methodName)
                .lowCardinalityKeyValue("class", className)
                .lowCardinalityKeyValue("method", methodName)
                .observe(() -> {
                    try {
                        return processRequest(joinPoint, fullMethodPath);
                    } catch (Throwable _) {
                        throw new ServiceException(CommonCode.ERROR);
                    }
                });
    }

    /**
     * 处理实际请求并增强响应
     *
     * @param joinPoint      连接点
     * @param fullMethodPath 完整方法路径
     * @return 增强后的响应
     * @throws Throwable 如果方法执行出错
     */
    private Object processRequest(ProceedingJoinPoint joinPoint, String fullMethodPath) throws Throwable {
        // 获取跟踪信息
        String traceId = getTraceId();
        String spanId = getSpanId();

        // 性能计时
        StopWatch stopWatch = new StopWatch(fullMethodPath);
        stopWatch.start("controller");

        try {
            log.info("⟹ 开始处理请求: {}, traceId=[{}], spanId=[{}]", fullMethodPath, traceId, spanId);

            // 执行原始方法
            Object result = joinPoint.proceed();

            // 只有当结果是Result类型时才增强响应
            enhanceResultIfPossible(result, traceId, spanId);

            stopWatch.stop();

            // 记录完成日志
            log.info("⟸ 请求处理完成: {}, 耗时={}ms, traceId=[{}], spanId=[{}], 响应={}",
                    fullMethodPath,
                    stopWatch.getTotalTimeMillis(),
                    traceId,
                    spanId,
                    result != null ? JSON.toJSONString(result) : "null"
            );

            return result;

        } catch (Exception e) {
            stopWatch.stop();
            log.error("⨯ 请求处理异常: {}, 耗时={}ms, traceId=[{}], spanId=[{}], 异常={}",
                    fullMethodPath,
                    stopWatch.getTotalTimeMillis(),
                    traceId,
                    spanId,
                    e.getMessage(),
                    e
            );
            throw e;
        }
    }

    /**
     * 为Result类型的响应添加跟踪信息
     *
     * @param result  原始响应对象
     * @param traceId 跟踪ID
     * @param spanId  跨度ID
     */
    private void enhanceResultIfPossible(Object result, String traceId, String spanId) {
        if (result instanceof Result<?> resultObj) {
            resultObj.setTraceId(traceId);
            resultObj.setSpanId(spanId);
            resultObj.setTimestamp(Instant.now().getEpochSecond());
        }
    }

    /**
     * 获取当前的跟踪ID
     *
     * @return 跟踪ID，如果不存在则返回空字符串
     */
    private String getTraceId() {
        return Optional.ofNullable(tracer)
                .map(Tracer::currentSpan)
                .map(span -> span.context().traceId())
                .orElse("");
    }

    /**
     * 获取当前的跨度ID
     *
     * @return 跨度ID，如果不存在则返回空字符串
     */
    private String getSpanId() {
        return Optional.ofNullable(tracer)
                .map(Tracer::currentSpan)
                .map(span -> span.context().spanId())
                .orElse("");
    }
}